#include "GMatrix4x4.h"

#include "GMath.h"
#include <memory.h>

namespace GMath
{

	const GMatrix4x4 GMatrix4x4::Identity = GMatrix4x4(	1.0f, 0.0f, 0.0f, 0.0f,
														0.0f, 1.0f, 0.0f, 0.0f,
														0.0f, 0.0f, 1.0f, 0.0f,
														0.0f, 0.0f, 0.0f, 1.0f );

	const GMatrix4x4 GMatrix4x4::Zero = GMatrix4x4(	0.0f, 0.0f, 0.0f, 0.0f,
													0.0f, 0.0f, 0.0f, 0.0f,
													0.0f, 0.0f, 0.0f, 0.0f,
													0.0f, 0.0f, 0.0f, 0.0f );

	const GMatrix4x4 GMatrix4x4::One = GMatrix4x4(	1.0f, 1.0f, 1.0f, 1.0f,
													1.0f, 1.0f, 1.0f, 1.0f,
													1.0f, 1.0f, 1.0f, 1.0f,
													1.0f, 1.0f, 1.0f, 1.0f );

	GMatrix4x4::GMatrix4x4()
	{
		I11 = 1.0f; I12 = 0.0f; I13 = 0.0f; I14 = 0.0f; 
		I21 = 0.0f; I22 = 1.0f; I23 = 0.0f; I24 = 0.0f; 
		I31 = 0.0f; I32 = 0.0f; I33 = 1.0f; I34 = 0.0f; 
		I41 = 0.0f; I42 = 0.0f; I43 = 0.0f; I44 = 1.0f;
	}

	GMatrix4x4::GMatrix4x4(float M11, float M12, float M13, float M14, 
						   float M21, float M22, float M23, float M24, 
						   float M31, float M32, float M33, float M34, 
						   float M41, float M42, float M43, float M44)
	{
		I11 = M11; I12 = M12; I13 = M13; I14 = M14; 
		I21 = M21; I22 = M22; I23 = M23; I24 = M24; 
		I31 = M31; I32 = M32; I33 = M33; I34 = M34; 
		I41 = M41; I42 = M42; I43 = M43; I44 = M44;
	}

	GMatrix4x4::operator float* ()
	{
		return Arr;
	}

	GMatrix4x4::operator const float* () const
	{
		return (const float*) Arr;
	}

	float GMatrix4x4::Determinant() const
	{
		float _3142_3241 = I31 * I42 - I32 * I41;
		float _3143_3341 = I31 * I43 - I33 * I41;
		float _3144_3441 = I31 * I44 - I34 * I41;
		float _3243_3342 = I32 * I43 - I33 * I42;
		float _3244_3442 = I32 * I44 - I34 * I42;
		float _3344_3443 = I33 * I44 - I34 * I43;

		return I11 * (I22 * _3344_3443 - I23 * _3244_3442 + I24 * _3243_3342)
			 - I12 * (I21 * _3344_3443 - I23 * _3144_3441 + I24 * _3143_3341)
			 + I13 * (I21 * _3244_3442 - I22 * _3144_3441 + I24 * _3142_3241)
			 - I14 * (I21 * _3243_3342 - I22 * _3143_3341 + I23 * _3142_3241);
	}

	bool GMatrix4x4::Inverse()
	{
		GMatrix4x4 Temp(*this);

		return Inverse(*this, Temp);
	}

	bool GMatrix4x4::Inverse(OUTPUT GMatrix4x4& OutMatrix, const GMatrix4x4& Matrix)
	{
		float Det = Matrix.Determinant();

		if (EqualF(Det, 0.0f))
		{
			return false;
		}

		float InvDet = 1.0f / Det;

		float _2132_2231 = Matrix.I21 * Matrix.I32 - Matrix.I22 * Matrix.I31;
		float _2133_2331 = Matrix.I21 * Matrix.I33 - Matrix.I23 * Matrix.I31;
		float _2134_2431 = Matrix.I21 * Matrix.I34 - Matrix.I24 * Matrix.I31;
		float _2142_2241 = Matrix.I21 * Matrix.I42 - Matrix.I22 * Matrix.I41;
		float _2143_2341 = Matrix.I21 * Matrix.I43 - Matrix.I23 * Matrix.I41;
		float _2144_2441 = Matrix.I21 * Matrix.I44 - Matrix.I24 * Matrix.I41;
		float _2233_2332 = Matrix.I22 * Matrix.I33 - Matrix.I23 * Matrix.I32;
		float _2234_2432 = Matrix.I22 * Matrix.I34 - Matrix.I24 * Matrix.I32;
		float _2243_2342 = Matrix.I22 * Matrix.I43 - Matrix.I23 * Matrix.I42;
		float _2244_2442 = Matrix.I22 * Matrix.I44 - Matrix.I24 * Matrix.I42;
		float _2334_2433 = Matrix.I23 * Matrix.I34 - Matrix.I24 * Matrix.I33;
		float _2344_2443 = Matrix.I23 * Matrix.I44 - Matrix.I24 * Matrix.I43;
		float _3142_3241 = Matrix.I31 * Matrix.I42 - Matrix.I32 * Matrix.I41;
		float _3143_3341 = Matrix.I31 * Matrix.I43 - Matrix.I33 * Matrix.I41;
		float _3144_3441 = Matrix.I31 * Matrix.I44 - Matrix.I34 * Matrix.I41;
		float _3243_3342 = Matrix.I32 * Matrix.I43 - Matrix.I33 * Matrix.I42;
		float _3244_3442 = Matrix.I32 * Matrix.I44 - Matrix.I34 * Matrix.I42;
		float _3344_3443 = Matrix.I32 * Matrix.I44 - Matrix.I34 * Matrix.I43;

		OutMatrix.I11 = +InvDet * (Matrix.I22 * _3344_3443 - Matrix.I23 * _3244_3442 + Matrix.I24 * _3243_3342);
		OutMatrix.I12 = -InvDet * (Matrix.I12 * _3344_3443 - Matrix.I13 * _3244_3442 + Matrix.I14 * _3243_3342);
		OutMatrix.I13 = +InvDet * (Matrix.I12 * _2344_2443 - Matrix.I13 * _2244_2442 + Matrix.I14 * _2243_2342);
		OutMatrix.I14 = -InvDet * (Matrix.I12 * _2334_2433 - Matrix.I13 * _2234_2432 + Matrix.I14 * _2233_2332);

		OutMatrix.I21 = -InvDet * (Matrix.I21 * _3344_3443 - Matrix.I23 * _3144_3441 + Matrix.I24 * _3143_3341);
		OutMatrix.I22 = +InvDet * (Matrix.I11 * _3344_3443 - Matrix.I13 * _3144_3441 + Matrix.I14 * _3143_3341);
		OutMatrix.I23 = -InvDet * (Matrix.I11 * _2344_2443 - Matrix.I13 * _2144_2441 + Matrix.I14 * _2143_2341);
		OutMatrix.I24 = +InvDet * (Matrix.I11 * _2334_2433 - Matrix.I13 * _2134_2431 + Matrix.I14 * _2133_2331);

		OutMatrix.I31 = +InvDet * (Matrix.I21 * _3244_3442 - Matrix.I22 * _3144_3441 + Matrix.I24 * _3142_3241);
		OutMatrix.I32 = -InvDet * (Matrix.I11 * _3244_3442 - Matrix.I12 * _3144_3441 + Matrix.I14 * _3142_3241);
		OutMatrix.I33 = +InvDet * (Matrix.I11 * _2244_2442 - Matrix.I12 * _2144_2441 + Matrix.I14 * _2142_2241);
		OutMatrix.I34 = -InvDet * (Matrix.I11 * _2234_2432 - Matrix.I12 * _2134_2431 + Matrix.I14 * _2132_2231);

		OutMatrix.I41 = -InvDet * (Matrix.I21 * _3243_3342 - Matrix.I22 * _3143_3341 + Matrix.I23 * _3142_3241);
		OutMatrix.I42 = +InvDet * (Matrix.I11 * _3243_3342 - Matrix.I12 * _3143_3341 + Matrix.I13 * _3142_3241);
		OutMatrix.I43 = -InvDet * (Matrix.I11 * _2243_2342 - Matrix.I12 * _2143_2341 + Matrix.I13 * _2142_2241);
		OutMatrix.I44 = +InvDet * (Matrix.I11 * _2233_2332 - Matrix.I12 * _2133_2331 + Matrix.I13 * _2132_2231);

		return true;
	}

	void GMatrix4x4::Transpose()
	{
		GMatrix4x4 Temp(*this);
		
		Transpose(*this, Temp);
	}

	void GMatrix4x4::Transpose(OUTPUT GMatrix4x4& OutMatrix, const GMatrix4x4& Matrix)
	{		
		OutMatrix.Arr[0]  = Matrix.Arr[0];
		OutMatrix.Arr[1]  = Matrix.Arr[4];
		OutMatrix.Arr[2]  = Matrix.Arr[8];
		OutMatrix.Arr[3]  = Matrix.Arr[12];
		OutMatrix.Arr[4]  = Matrix.Arr[1];
		OutMatrix.Arr[5]  = Matrix.Arr[5];
		OutMatrix.Arr[6]  = Matrix.Arr[9];
		OutMatrix.Arr[7]  = Matrix.Arr[13];
		OutMatrix.Arr[8]  = Matrix.Arr[2];
		OutMatrix.Arr[9]  = Matrix.Arr[6];
		OutMatrix.Arr[10] = Matrix.Arr[10];
		OutMatrix.Arr[11] = Matrix.Arr[14];
		OutMatrix.Arr[12] = Matrix.Arr[3];
		OutMatrix.Arr[13] = Matrix.Arr[7];
		OutMatrix.Arr[14] = Matrix.Arr[11];
		OutMatrix.Arr[15] = Matrix.Arr[15];
	}

	static inline GUInt32 IndexOfMax(float I0, float I1, float I2)
	{
		if (I0 > I1)
		{
			return I0 > I2 ? 0 : 2;
		}
		else
		{
			return I1 > I2 ? 1 : 2;
		}
	}

	void GMatrix4x4::Convert(OUTPUT GQuaternion& OutQuaternion, const GMatrix4x4& Matrix)
	{
		float T = Matrix.I11 + Matrix.I22 + Matrix.I33 + Matrix.I44;

		if (T > 0.0f)
		{
			float S = 0.5f / SqrtF(T);
			OutQuaternion.x = S * (Matrix.I32 - Matrix.I23);
			OutQuaternion.y = S * (Matrix.I13 - Matrix.I31);
			OutQuaternion.z = S * (Matrix.I21 - Matrix.I12);
			OutQuaternion.w = 0.25f / S;
		}
		else
		{
			GUInt32 Index = IndexOfMax(Matrix.I11, Matrix.I22, Matrix.I33);
		
			switch (Index)
			{
				case 0:
				{
					float S = SqrtF(1.0f + Matrix.I11 - Matrix.I22 - Matrix.I33) * 2.0f;
					OutQuaternion.x = 0.5f / S;
					OutQuaternion.y = (Matrix.I12 + Matrix.I21) / S;
					OutQuaternion.z = (Matrix.I13 + Matrix.I31) / S;
					OutQuaternion.w = (Matrix.I23 + Matrix.I32) / S;
					break;
				}
				case 1:
				{
					float S = SqrtF(1.0f + Matrix.I22 - Matrix.I11 - Matrix.I33) * 2.0f;
					OutQuaternion.x = (Matrix.I12 + Matrix.I21) / S;
					OutQuaternion.y = 0.5f / S;
					OutQuaternion.z = (Matrix.I23 + Matrix.I32) / S;
					OutQuaternion.w = (Matrix.I13 + Matrix.I31) / S;
					break;
				}
				case 2:
				{
					float S = SqrtF(1.0f + Matrix.I33 - Matrix.I11 - Matrix.I22) * 2.0f;
					OutQuaternion.x = (Matrix.I13 + Matrix.I31) / S;
					OutQuaternion.y = (Matrix.I23 + Matrix.I32) / S;
					OutQuaternion.z = 0.5f / S;
					OutQuaternion.w = (Matrix.I12 + Matrix.I21) / S;
					break;
				}
			}
		}

		OutQuaternion.Normalize();
	}

	void GMatrix4x4::Convert(OUTPUT GMatrix4x4& OutMatrix, const GQuaternion& Quaternion)
	{
		float xx = Quaternion.x * Quaternion.x;
		float yy = Quaternion.y * Quaternion.y;
		float zz = Quaternion.z * Quaternion.z;
		float xy = Quaternion.x * Quaternion.y;
		float xz = Quaternion.x * Quaternion.z;
		float xw = Quaternion.x * Quaternion.w;
		float yz = Quaternion.y * Quaternion.z;
		float yw = Quaternion.y * Quaternion.w;
		float zw = Quaternion.z * Quaternion.w;

		OutMatrix.I11 = 1.0f - 2.0f * (yy - zz);
		OutMatrix.I12 = 2.0f * (xy - zw);
		OutMatrix.I13 =	2.0f * (xz + yw);
		OutMatrix.I14 = 0.0f;

		OutMatrix.I21 =	2.0f * (xy + zw);	
		OutMatrix.I22 = 1.0f - 2.0f * (xx - zz);	
		OutMatrix.I23 =	2.0f * (yz + xw);	
		OutMatrix.I24 = 0.0f;

		OutMatrix.I31 =	2.0f * (xz - yw);
		OutMatrix.I32 =	2.0f * (yz - xw);
		OutMatrix.I33 = 1.0f - 2.0f * (xx - yy);
		OutMatrix.I34 = 0.0f;

		OutMatrix.I41 = 0.0f;
		OutMatrix.I42 = 0.0f;
		OutMatrix.I43 = 0.0f;
		OutMatrix.I44 = 1.0f;
	}

	void GMatrix4x4::Decompose(OUTPUT GVector3& OutScale, OUTPUT GQuaternion& OutRotation, OUTPUT GVector3& OutTranslation, const GMatrix4x4& Matrix)
	{
		OutScale.x = SqrtF(Matrix.I11 * Matrix.I11 + Matrix.I12 * Matrix.I12 + Matrix.I13 * Matrix.I13);
		OutScale.y = SqrtF(Matrix.I21 * Matrix.I21 + Matrix.I22 * Matrix.I22 + Matrix.I23 * Matrix.I23);
		OutScale.z = SqrtF(Matrix.I31 * Matrix.I31 + Matrix.I32 * Matrix.I32 + Matrix.I33 * Matrix.I33);

		OutTranslation.x = Matrix.I41;
		OutTranslation.y = Matrix.I42;
		OutTranslation.z = Matrix.I43;
	
		GMatrix4x4 MatRotation;
		MatRotation.I11 = Matrix.I11 / OutScale.x;
		MatRotation.I12 = Matrix.I12 / OutScale.x;
		MatRotation.I13 = Matrix.I13 / OutScale.x;
		MatRotation.I14 = 0.0f;
		MatRotation.I21 = Matrix.I21 / OutScale.y;
		MatRotation.I22 = Matrix.I22 / OutScale.y;
		MatRotation.I23 = Matrix.I23 / OutScale.y;
		MatRotation.I24 = 0.0f;
		MatRotation.I31 = Matrix.I31 / OutScale.z;
		MatRotation.I32 = Matrix.I32 / OutScale.z;
		MatRotation.I33 = Matrix.I33 / OutScale.z;
		MatRotation.I34 = 0.0f;
		MatRotation.I41 = 0.0f;
		MatRotation.I42 = 0.0f;
		MatRotation.I43 = 0.0f;
		MatRotation.I44 = 1.0f;

		GMatrix4x4::Convert(OutRotation, MatRotation);
	}

	// For vector rotations
	void GMatrix4x4::Multiply(OUTPUT GVector3& Output, const GVector3& Vector, const GMatrix4x4& Matrix)
	{
		Output.x = (Vector.x * Matrix.I11) + (Vector.y * Matrix.I21) + (Vector.z * Matrix.I31);
		Output.y = (Vector.x * Matrix.I12) + (Vector.y * Matrix.I22) + (Vector.z * Matrix.I32);
		Output.z = (Vector.x * Matrix.I13) + (Vector.y * Matrix.I23) + (Vector.z * Matrix.I33);
	}

	// For point translations
	void GMatrix4x4::Multiply(OUTPUT GVector4& Output, const GVector4& Vector, const GMatrix4x4& Matrix)
	{
		Output = Vector * Matrix;
		/*
		Output.x = (Vector.x * Matrix.I11) + (Vector.y * Matrix.I21) + (Vector.z * Matrix.I31) + (Vector.w * Matrix.I41);
		Output.y = (Vector.x * Matrix.I12) + (Vector.y * Matrix.I22) + (Vector.z * Matrix.I32) + (Vector.w * Matrix.I42);
		Output.z = (Vector.x * Matrix.I13) + (Vector.y * Matrix.I23) + (Vector.z * Matrix.I33) + (Vector.w * Matrix.I43);
		Output.w = (Vector.x * Matrix.I14) + (Vector.y * Matrix.I24) + (Vector.z * Matrix.I34) + (Vector.w * Matrix.I44);
		*/
	}
		
	void GMatrix4x4::Multiply(OUTPUT GMatrix4x4& Output, const GMatrix4x4& MatrixA, const GMatrix4x4& MatrixB)
	{
		Output = MatrixA * MatrixB;

		/*
		for (GUInt32 I=0; I<16; I+=4)
		{
			for (GUInt32 J=0; J<4; J++) 
			{
				Output[I+J] =	MatrixB.Arr[I+0] * MatrixA.Arr[J+0] + 
								MatrixB.Arr[I+1] * MatrixA.Arr[J+4] + 
								MatrixB.Arr[I+2] * MatrixA.Arr[J+8] + 
								MatrixB.Arr[I+3] * MatrixA.Arr[J+12];
			}
		}
		*/
	}

	float GMatrix4x4::operator () (GUInt32 Row, GUInt32 Column)
	{
		return Mat[Row][Column];
	}
	
	float GMatrix4x4::operator () (GUInt32 Row, GUInt32 Column) const
	{
		return Mat[Row][Column];
	}

	GMatrix4x4& GMatrix4x4::operator = (const GMatrix4x4& Matrix)
	{
		memcpy(Arr, Matrix.Arr, sizeof(float) * 16);
		return *this;
	}

	GMatrix4x4& GMatrix4x4::operator += (const GMatrix4x4& Matrix)
	{
		I11 += Matrix.I11; I12 += Matrix.I12; I13 += Matrix.I13; I14 += Matrix.I14;
		I21 += Matrix.I21; I22 += Matrix.I22; I23 += Matrix.I23; I24 += Matrix.I24;
		I31 += Matrix.I31; I32 += Matrix.I32; I33 += Matrix.I33; I34 += Matrix.I34;
		I41 += Matrix.I41; I42 += Matrix.I42; I43 += Matrix.I43; I44 += Matrix.I44;
		return *this;
	}

	GMatrix4x4& GMatrix4x4::operator -= (const GMatrix4x4& Matrix)
	{
		I11 -= Matrix.I11; I12 -= Matrix.I12; I13 -= Matrix.I13; I14 -= Matrix.I14;
		I21 -= Matrix.I21; I22 -= Matrix.I22; I23 -= Matrix.I23; I24 -= Matrix.I24;
		I31 -= Matrix.I31; I32 -= Matrix.I32; I33 -= Matrix.I33; I34 -= Matrix.I34;
		I41 -= Matrix.I41; I42 -= Matrix.I42; I43 -= Matrix.I43; I44 -= Matrix.I44;
		return *this;
	}


	// to achieve scale > rotate > translate sequence you should follow
	// transform = Translate * Rotate * Scale multiplication order.
	GMatrix4x4& GMatrix4x4::operator *= (const GMatrix4x4& Matrix)
	{
		GMatrix4x4 Temp(*this);
		
		for (int I = 0; I < 16; I += 4)
		{
			for (int J = 0; J < 4; J++)
			{
				Arr[I+J] =	Temp.Arr[I+0] * Matrix.Arr[J+0] + 
							Temp.Arr[I+1] * Matrix.Arr[J+4] + 
							Temp.Arr[I+2] * Matrix.Arr[J+8] + 
							Temp.Arr[I+3] * Matrix.Arr[J+12];
			}
		}
		return *this;
	}

	GMatrix4x4& GMatrix4x4::operator *= (const float Value)
	{
		I11 *= Value; I12 *= Value; I13 *= Value; I14 *= Value;
		I21 *= Value; I22 *= Value; I23 *= Value; I24 *= Value;
		I31 *= Value; I32 *= Value; I33 *= Value; I34 *= Value;
		I41 *= Value; I42 *= Value; I43 *= Value; I44 *= Value;
		return *this;
	}

	GMatrix4x4& GMatrix4x4::operator /= (const float Value)
	{
		float Inverse = 1.0f / Value;
		I11 *= Inverse; I12 *= Inverse; I13 *= Inverse; I14 *= Inverse;
		I21 *= Inverse; I22 *= Inverse; I23 *= Inverse; I24 *= Inverse;
		I31 *= Inverse; I32 *= Inverse; I33 *= Inverse; I34 *= Inverse;
		I41 *= Inverse; I42 *= Inverse; I43 *= Inverse; I44 *= Inverse;
		return *this;
	}

	GMatrix4x4 GMatrix4x4::operator + (const GMatrix4x4& Matrix) const
	{
		return GMatrix4x4(	I11 + Matrix.I11, I12 + Matrix.I12, I13 + Matrix.I13, I14 + Matrix.I14,
							I21 + Matrix.I21, I22 + Matrix.I22, I23 + Matrix.I23, I24 + Matrix.I24,
							I31 + Matrix.I31, I32 + Matrix.I32, I33 + Matrix.I33, I34 + Matrix.I34,
							I41 + Matrix.I41, I42 + Matrix.I42, I43 + Matrix.I43, I44 + Matrix.I44);
	}

	GMatrix4x4 GMatrix4x4::operator - (const GMatrix4x4& Matrix) const
	{
		return GMatrix4x4(	I11 - Matrix.I11, I12 - Matrix.I12, I13 - Matrix.I13, I14 - Matrix.I14,
							I21 - Matrix.I21, I22 - Matrix.I22, I23 - Matrix.I23, I24 - Matrix.I24,
							I31 - Matrix.I31, I32 - Matrix.I32, I33 - Matrix.I33, I34 - Matrix.I34,
							I41 - Matrix.I41, I42 - Matrix.I42, I43 - Matrix.I43, I44 - Matrix.I44);
	}

	GMatrix4x4 GMatrix4x4::operator * (const GMatrix4x4& Matrix) const
	{
		GMatrix4x4 TempMatrix;
		
		for (GUInt32 I = 0; I < 16; I += 4)
		{
			for (GUInt32 J = 0; J < 4; J++) 
			{
				TempMatrix[I+J] =	Arr[I+0] * Matrix.Arr[J+0] + 
									Arr[I+1] * Matrix.Arr[J+4] + 
									Arr[I+2] * Matrix.Arr[J+8] + 
									Arr[I+3] * Matrix.Arr[J+12];
			}
		}
		return TempMatrix;
	}

	GMatrix4x4 GMatrix4x4::operator * (const float Value) const
	{
		return GMatrix4x4(	I11 * Value, I12 * Value, I13 * Value, I14 * Value,
							I21 * Value, I22 * Value, I23 * Value, I24 * Value,
							I31 * Value, I32 * Value, I33 * Value, I34 * Value,
							I41 * Value, I42 * Value, I43 * Value, I44 * Value);
	}

	GMatrix4x4 GMatrix4x4::operator / (const float Value) const
	{
		float Inverse = 1.0f / Value;
		return GMatrix4x4(	I11 * Inverse, I12 * Inverse, I13 * Inverse, I14 * Inverse,
							I21 * Inverse, I22 * Inverse, I23 * Inverse, I24 * Inverse,
							I31 * Inverse, I32 * Inverse, I33 * Inverse, I34 * Inverse,
							I41 * Inverse, I42 * Inverse, I43 * Inverse, I44 * Inverse);
	}

	GMatrix4x4 GMatrix4x4::operator + () const
	{
		return *this;
	}

	GMatrix4x4 GMatrix4x4::operator - () const
	{
		return GMatrix4x4(	-I11, -I12, -I13, -I14,
							-I21, -I22, -I23, -I24,
							-I31, -I32, -I33, -I34,
							-I41, -I42, -I43, -I44);
	}

	bool GMatrix4x4::operator == (const GMatrix4x4& Matrix) const
	{
		for (GUInt32 I = 0; I < 16; ++I)
		{
			if (!EqualF(Arr[I], Matrix.Arr[I]))
				return false;
		}

		return true;
	}

	bool GMatrix4x4::operator != (const GMatrix4x4& Matrix) const
	{
		return !operator ==(Matrix);
	}

	GMatrix4x4 operator * (float Value, const GMatrix4x4& Matrix)
	{
		return GMatrix4x4(	Value * Matrix.I11, Value * Matrix.I12, Value * Matrix.I13, Value * Matrix.I14,
							Value * Matrix.I21, Value * Matrix.I22, Value * Matrix.I23, Value * Matrix.I24,
							Value * Matrix.I31, Value * Matrix.I32, Value * Matrix.I33, Value * Matrix.I34,
							Value * Matrix.I41, Value * Matrix.I42, Value * Matrix.I43, Value * Matrix.I44);
	}

	GVector4 operator * (const GVector4& Vector, const GMatrix4x4& Matrix)
	{
		GVector4 Output;
		Output.x = (Vector.x * Matrix.I11) + (Vector.y * Matrix.I21) + (Vector.z * Matrix.I31) + (Vector.w * Matrix.I41);
		Output.y = (Vector.x * Matrix.I12) + (Vector.y * Matrix.I22) + (Vector.z * Matrix.I32) + (Vector.w * Matrix.I42);
		Output.z = (Vector.x * Matrix.I13) + (Vector.y * Matrix.I23) + (Vector.z * Matrix.I33) + (Vector.w * Matrix.I43);
		Output.w = (Vector.x * Matrix.I14) + (Vector.y * Matrix.I24) + (Vector.z * Matrix.I34) + (Vector.w * Matrix.I44);
		return Output;
	}

	GVector3 operator * (const GVector3& Vector, const GMatrix4x4& Matrix)
	{
		GVector3 Output;
		Output.x = (Vector.x * Matrix.I11) + (Vector.y * Matrix.I21) + (Vector.z * Matrix.I31);
		Output.y = (Vector.x * Matrix.I12) + (Vector.y * Matrix.I22) + (Vector.z * Matrix.I32);
		Output.z = (Vector.x * Matrix.I13) + (Vector.y * Matrix.I23) + (Vector.z * Matrix.I33);
		return Output;
	}

}